
/**
  ******************************************************************************
  * Copyright 2021 The Microbee Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       dev_mgr.c
  * @author     baiyang
  * @date       2021-10-20
  ******************************************************************************
  */

/*----------------------------------include-----------------------------------*/
#include <stdio.h>
#include <string.h>

#include "dev_mgr.h"
#include "dev_mgr_i2c.h"
#include "dev_mgr_spi.h"

#include <common/console/console.h>
/*-----------------------------------macro------------------------------------*/

/*----------------------------------typedef-----------------------------------*/

/*---------------------------------prototype----------------------------------*/

/*----------------------------------variable----------------------------------*/
struct gp_device *devmgr_spi_dev;
struct gp_device *devmgr_i2c_dev;
/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
/**
  * @brief       
  * @param[in]   name  
  * @param[out]  
  * @retval      
  * @note        
  */
gp_device_t devmgr_get_spi_device(const char *name)
{
    rt_device_t rt_dev = rt_device_find(name);
    gp_device_t _dev;

    if (rt_dev == NULL) {
        return NULL;
    }

    // find a callback to run
    for (_dev = devmgr_spi_dev; _dev; _dev = _dev->next) {
        if (_dev->dev == rt_dev) {
            return _dev;
        }
    }

    if ((rt_dev->open_flag & RT_DEVICE_OFLAG_OPEN) != RT_DEVICE_OFLAG_OPEN && rt_device_open(rt_dev , RT_DEVICE_OFLAG_RDWR) != RT_EOK) {
        return NULL;
    }

    _dev = (struct gp_device *)rt_malloc(sizeof(struct gp_device));

    /* clean memory data of object */
    rt_memset(_dev, 0, sizeof(struct gp_device));

    if (_dev == NULL) {
        console_panic("function:%s, line number:%d, %s malloc failure\n",__FUNCTION__, __LINE__, name);
        return NULL;
    }

    _dev->dev = rt_dev;

    // add to linked list of callbacks on thread
    _dev->next = devmgr_spi_dev;
    devmgr_spi_dev = _dev;

    devmgr_config_spi_dev(_dev);

    return _dev;
}

/**
  * @brief       
  * @param[in]   bus  
  * @param[in]   address  
  * @param[out]  
  * @retval      
  * @note        
  */
gp_device_t devmgr_get_i2c_device(uint8_t bus, uint8_t address)
{
    gp_device_t _dev;
    
    char name[20];
    rt_memset(name, 0, sizeof(name));
    
    snprintf(name, sizeof(name), "i2c%u",bus + 1);
    rt_device_t rt_dev = rt_device_find(name);

    if (rt_dev == NULL) {
        //console_printf("function:%s, line number:%d, %s find failure\n",__FUNCTION__, __LINE__, name);
        return NULL;
    }


    // find a callback to run
    for (_dev = devmgr_i2c_dev; _dev; _dev = _dev->next) {
        if (_dev != NULL && _dev->dev == rt_dev && _dev->_address == address) {
            return _dev;
        }
    }

    if ((rt_dev->open_flag & RT_DEVICE_OFLAG_OPEN) != RT_DEVICE_OFLAG_OPEN && rt_device_open(rt_dev , RT_DEVICE_OFLAG_RDWR) != RT_EOK) {
        return NULL;
    }

    _dev = (struct gp_device *)rt_malloc(sizeof(struct gp_device));

    /* clean memory data of object */
    rt_memset(_dev, 0, sizeof(struct gp_device));

    if (_dev == NULL) {
        console_panic("function:%s, line number:%d, %s malloc failure\n",__FUNCTION__, __LINE__, name);
        return NULL;
    }

    _dev->dev = rt_dev;

    // add to linked list of callbacks on thread
    _dev->next = devmgr_i2c_dev;
    devmgr_i2c_dev = _dev;

    devmgr_i2c_config(_dev, bus, address);

    return _dev;
}

/**
  * @brief       
  * @param[in]   dev  
  * @param[in]   devtype  
  * @param[out]  
  * @retval      
  * @note        
  */
uint32_t devmgr_get_bus_id_devtype(gp_device_t dev, uint8_t devtype)
{
    RT_ASSERT(dev != RT_NULL);

    union DeviceId d = dev->d;
    d.devid_s.devtype = devtype;

    return d.devid;
}

/**
  * @brief       
  * @param[in]   dev  
  * @param[in]   devtype  
  * @param[out]  
  * @retval      
  * @note        
  */
bool devmgr_set_speed(gp_device_t dev, enum DeviceSpeed speed)
{
    rt_err_t ret = RT_EOK;

#if defined(RT_USING_SPI)
    struct rt_spi_configuration cfg;

    RT_ASSERT(dev != RT_NULL);

    if (devmgr_get_bus_type(dev) == BUS_TYPE_SPI) {

        cfg.data_width = dev->spi_data_width;
        cfg.mode = dev->spi_mode;
        cfg.max_hz = (speed == DEV_SPEED_LOW ? dev->spi_freq_low : dev->spi_freq_high);

        ret |= rt_spi_configure((struct rt_spi_device*)dev->dev, &cfg);
    }
#else
    (void)dev;
    (void)speed;
#endif
    return (ret == RT_EOK);
}

/**
 * Some devices connected on the I2C or SPI bus require a bit to be set on
 * the register address in order to perform a read operation. This sets a
 * flag to be used by #read_registers(). The flag's default value is zero.
 */
void devmgr_set_read_flag(gp_device_t dev, uint8_t flag)
{
    RT_ASSERT(dev != RT_NULL);

    dev->_read_flag = flag;
}
/*------------------------------------test------------------------------------*/


